Skip to content

Conversation

codeflash-ai[bot]
Copy link
Contributor

@codeflash-ai codeflash-ai bot commented Sep 3, 2025

⚡️ This pull request contains optimizations for PR #687

If you approve this dependent PR, these changes will be merged into the original PR branch granular-async-instrumentation.

This PR will be automatically closed if the original PR is merged.


📄 11% (0.11x) speedup for CommentMapper.visit_AsyncFunctionDef in codeflash/code_utils/edit_generated_tests.py

⏱️ Runtime : 3.58 milliseconds 3.22 milliseconds (best of 291 runs)

📝 Explanation and details

The optimized code achieves an 11% speedup through several key micro-optimizations that reduce Python's runtime overhead:

1. Cached Attribute/Dictionary Lookups
The most impactful change is caching frequently accessed attributes and dictionaries as local variables:

  • context_stack = self.context_stack
  • results = self.results
  • original_runtimes = self.original_runtimes
  • optimized_runtimes = self.optimized_runtimes
  • get_comment = self.get_comment

This eliminates repeated self. attribute lookups in the tight loops, which the profiler shows are called thousands of times (2,825+ iterations).

2. Pre-cached Loop Bodies
Caching node_body = node.body and ln_body = line_node.body before loops reduces attribute access overhead. The profiler shows these are accessed in nested loops with high hit counts.

3. Optimized String Operations
Using f-strings (f"{test_qualified_name}#{self.abs_path}", f"{i}_{j}") instead of string concatenation with + operators reduces temporary object creation and string manipulation overhead.

4. Refined getattr Usage
Changed from getattr(compound_line_node, "body", []) to getattr(compound_line_node, 'body', None) with a conditional check, avoiding allocation of empty lists when no body exists.

Performance Impact by Test Type:

  • Large-scale tests show the biggest gains (14-117% faster) due to the cumulative effect of micro-optimizations in loops
  • Compound statement tests benefit significantly (16-45% faster) from reduced attribute lookups in nested processing
  • Simple cases show modest improvements (1-6% faster) as overhead reduction is less pronounced
  • Edge cases with no matching runtimes benefit from faster loop traversal (3-12% faster)

The optimizations are most effective for functions with many statements or nested compound structures, where the tight loops amplify the benefit of reduced Python interpreter overhead.

Correctness verification report:

Test Status
⚙️ Existing Unit Tests 🔘 None Found
🌀 Generated Regression Tests 68 Passed
⏪ Replay Tests 🔘 None Found
🔎 Concolic Coverage Tests 🔘 None Found
📊 Tests Coverage 100.0%
🌀 Generated Regression Tests and Runtime
from __future__ import annotations

import ast
from pathlib import Path

# imports
import pytest  # used for our unit tests
from codeflash.code_utils.edit_generated_tests import CommentMapper
from codeflash.code_utils.time_utils import format_perf, format_time
from codeflash.models.models import GeneratedTests
from codeflash.result.critic import performance_gain


class GeneratedTests:
    def __init__(self, behavior_file_path):
        self.behavior_file_path = Path(behavior_file_path)


# unit tests

# Helper to create AsyncFunctionDef nodes
def make_async_func(name, body):
    return ast.AsyncFunctionDef(
        name=name,
        args=ast.arguments(posonlyargs=[], args=[], kwonlyargs=[], kw_defaults=[], defaults=[]),
        body=body,
        decorator_list=[],
        returns=None,
        type_comment=None,
    )

# Helper to create simple statements
def make_assign(lineno):
    return ast.Assign(targets=[ast.Name(id='x', ctx=ast.Store())], value=ast.Constant(value=1), lineno=lineno)

def make_for(lineno, body):
    return ast.For(target=ast.Name(id='i', ctx=ast.Store()), iter=ast.Name(id='lst', ctx=ast.Load()), body=body, orelse=[], lineno=lineno)

def make_with(lineno, body):
    return ast.With(items=[ast.withitem(context_expr=ast.Name(id='lock', ctx=ast.Load()))], body=body, lineno=lineno)

def make_if(lineno, body):
    return ast.If(test=ast.Name(id='cond', ctx=ast.Load()), body=body, orelse=[], lineno=lineno)

def make_while(lineno, body):
    return ast.While(test=ast.Name(id='flag', ctx=ast.Load()), body=body, orelse=[], lineno=lineno)

# Basic Test Cases

def test_basic_single_statement():
    # Test with a single statement in async function
    func = make_async_func("foo", [make_assign(lineno=10)])
    test = GeneratedTests("file.py")
    key_base = "foo#file#0"
    original = {key_base: 100_000_000}
    optimized = {key_base: 50_000_000}
    mapper = CommentMapper(test, original, optimized)
    mapper.visit_AsyncFunctionDef(func) # 10.5μs -> 10.6μs (0.009% slower)

def test_basic_multiple_statements():
    # Test with multiple statements in async function
    func = make_async_func("bar", [make_assign(20), make_assign(21)])
    test = GeneratedTests("file.py")
    key_base = "bar#file"
    original = {f"{key_base}#1": 200_000_000, f"{key_base}#0": 100_000_000}
    optimized = {f"{key_base}#1": 150_000_000, f"{key_base}#0": 90_000_000}
    mapper = CommentMapper(test, original, optimized)
    mapper.visit_AsyncFunctionDef(func) # 12.8μs -> 12.9μs (0.622% slower)

def test_basic_for_loop():
    # Test with a for loop containing one statement
    for_body = [make_assign(30)]
    func = make_async_func("baz", [make_for(29, for_body)])
    test = GeneratedTests("file.py")
    key_base = "baz#file"
    original = {f"{key_base}#0_0": 300_000_000}
    optimized = {f"{key_base}#0_0": 250_000_000}
    mapper = CommentMapper(test, original, optimized)
    mapper.visit_AsyncFunctionDef(func) # 10.6μs -> 10.3μs (3.51% faster)

def test_basic_with_block():
    # Test with a with block containing one statement
    with_body = [make_assign(40)]
    func = make_async_func("qux", [make_with(39, with_body)])
    test = GeneratedTests("file.py")
    key_base = "qux#file"
    original = {f"{key_base}#0_0": 400_000_000}
    optimized = {f"{key_base}#0_0": 300_000_000}
    mapper = CommentMapper(test, original, optimized)
    mapper.visit_AsyncFunctionDef(func) # 10.1μs -> 9.92μs (1.62% faster)

# Edge Test Cases

def test_edge_no_body():
    # Test with an async function with no body
    func = make_async_func("empty", [])
    test = GeneratedTests("file.py")
    original = {}
    optimized = {}
    mapper = CommentMapper(test, original, optimized)
    mapper.visit_AsyncFunctionDef(func) # 3.57μs -> 3.85μs (7.28% slower)

def test_edge_missing_runtimes():
    # Test where runtime keys are missing
    func = make_async_func("foo", [make_assign(50)])
    test = GeneratedTests("file.py")
    original = {}
    optimized = {}
    mapper = CommentMapper(test, original, optimized)
    mapper.visit_AsyncFunctionDef(func) # 4.57μs -> 4.77μs (4.19% slower)

def test_edge_mismatched_runtimes():
    # Test where only one of the runtime dicts has the key
    func = make_async_func("foo", [make_assign(51)])
    test = GeneratedTests("file.py")
    key_base = "foo#file#0"
    original = {key_base: 100_000_000}
    optimized = {}
    mapper = CommentMapper(test, original, optimized)
    mapper.visit_AsyncFunctionDef(func) # 4.63μs -> 4.74μs (2.32% slower)

def test_edge_nested_compound_statement():
    # Test with nested compound statements (for inside if)
    inner_body = [make_assign(61)]
    if_body = [make_for(60, inner_body)]
    func = make_async_func("nested", [make_if(59, if_body)])
    test = GeneratedTests("file.py")
    key_base = "nested#file"
    original = {f"{key_base}#0_0": 500_000_000}
    optimized = {f"{key_base}#0_0": 400_000_000}
    mapper = CommentMapper(test, original, optimized)
    mapper.visit_AsyncFunctionDef(func) # 13.3μs -> 13.0μs (2.86% faster)

def test_edge_compound_with_multiple_statements():
    # Test with compound statement with multiple statements
    for_body = [make_assign(70), make_assign(71)]
    func = make_async_func("multi", [make_for(69, for_body)])
    test = GeneratedTests("file.py")
    key_base = "multi#file"
    original = {f"{key_base}#0_0": 600_000_000, f"{key_base}#0_1": 700_000_000}
    optimized = {f"{key_base}#0_0": 550_000_000, f"{key_base}#0_1": 650_000_000}
    mapper = CommentMapper(test, original, optimized)
    mapper.visit_AsyncFunctionDef(func) # 13.6μs -> 13.3μs (1.88% faster)

def test_edge_while_loop():
    # Test with a while loop containing a statement
    while_body = [make_assign(80)]
    func = make_async_func("whiler", [make_while(79, while_body)])
    test = GeneratedTests("file.py")
    key_base = "whiler#file"
    original = {f"{key_base}#0_0": 800_000_000}
    optimized = {f"{key_base}#0_0": 700_000_000}
    mapper = CommentMapper(test, original, optimized)
    mapper.visit_AsyncFunctionDef(func) # 10.0μs -> 10.00μs (0.410% faster)

def test_edge_slower_performance():
    # Test where optimized runtime is slower
    func = make_async_func("slow", [make_assign(90)])
    test = GeneratedTests("file.py")
    key_base = "slow#file#0"
    original = {key_base: 100_000_000}
    optimized = {key_base: 120_000_000}
    mapper = CommentMapper(test, original, optimized)
    mapper.visit_AsyncFunctionDef(func) # 8.95μs -> 9.04μs (0.996% slower)

def test_edge_zero_original_runtime():
    # Test where original runtime is zero
    func = make_async_func("zero", [make_assign(100)])
    test = GeneratedTests("file.py")
    key_base = "zero#file#0"
    original = {key_base: 0}
    optimized = {key_base: 0}
    mapper = CommentMapper(test, original, optimized)
    mapper.visit_AsyncFunctionDef(func) # 8.12μs -> 8.16μs (0.380% slower)

def test_edge_nested_body_attribute():
    # Test with compound statement whose body contains a compound statement
    inner_body = [make_assign(111)]
    with_body = [make_for(110, inner_body)]
    func = make_async_func("deep", [make_with(109, with_body)])
    test = GeneratedTests("file.py")
    key_base = "deep#file"
    original = {f"{key_base}#0_0": 900_000_000}
    optimized = {f"{key_base}#0_0": 800_000_000}
    mapper = CommentMapper(test, original, optimized)
    mapper.visit_AsyncFunctionDef(func) # 12.6μs -> 12.2μs (3.88% faster)

# Large Scale Test Cases

def test_large_many_statements():
    # Test with many statements in async function
    n = 500
    body = [make_assign(2000 + i) for i in range(n)]
    func = make_async_func("bigfunc", body)
    test = GeneratedTests("file.py")
    key_base = "bigfunc#file"
    original = {f"{key_base}#{i}": 1_000_000 + i*1000 for i in range(n)}
    optimized = {f"{key_base}#{i}": 900_000 + i*1000 for i in range(n)}
    mapper = CommentMapper(test, original, optimized)
    mapper.visit_AsyncFunctionDef(func) # 1.02ms -> 988μs (3.64% faster)
    for i in range(n):
        lineno = 2000 + i

def test_large_many_compound_statements():
    # Test with many for loops, each with one statement
    n = 200
    body = [make_for(3000 + i, [make_assign(4000 + i)]) for i in range(n)]
    func = make_async_func("bigcompound", body)
    test = GeneratedTests("file.py")
    key_base = "bigcompound#file"
    original = {f"{key_base}#{i}_0": 2_000_000 + i*1000 for i in range(n)}
    optimized = {f"{key_base}#{i}_0": 1_900_000 + i*1000 for i in range(n)}
    mapper = CommentMapper(test, original, optimized)
    mapper.visit_AsyncFunctionDef(func) # 509μs -> 480μs (5.96% faster)
    for i in range(n):
        lineno = 4000 + i

def test_large_nested_compound_statements():
    # Test with nested compound statements in large scale
    n = 100
    # Each if contains a for with one statement
    body = [make_if(5000 + i, [make_for(6000 + i, [make_assign(7000 + i)])]) for i in range(n)]
    func = make_async_func("bignested", body)
    test = GeneratedTests("file.py")
    key_base = "bignested#file"
    original = {f"{key_base}#{i}_0": 3_000_000 + i*1000 for i in range(n)}
    optimized = {f"{key_base}#{i}_0": 2_900_000 + i*1000 for i in range(n)}
    mapper = CommentMapper(test, original, optimized)
    mapper.visit_AsyncFunctionDef(func) # 460μs -> 423μs (8.82% faster)
    for i in range(n):
        lineno = 7000 + i

def test_large_no_runtimes():
    # Large function with no runtime data
    n = 300
    body = [make_assign(8000 + i) for i in range(n)]
    func = make_async_func("norun", body)
    test = GeneratedTests("file.py")
    original = {}
    optimized = {}
    mapper = CommentMapper(test, original, optimized)
    mapper.visit_AsyncFunctionDef(func) # 107μs -> 95.6μs (12.0% faster)

def test_large_partial_runtimes():
    # Large function with only some runtime data
    n = 400
    body = [make_assign(9000 + i) for i in range(n)]
    func = make_async_func("partial", body)
    test = GeneratedTests("file.py")
    key_base = "partial#file"
    # Only annotate even indices
    original = {f"{key_base}#{i}": 4_000_000 + i*1000 for i in range(n) if i % 2 == 0}
    optimized = {f"{key_base}#{i}": 3_900_000 + i*1000 for i in range(n) if i % 2 == 0}
    mapper = CommentMapper(test, original, optimized)
    mapper.visit_AsyncFunctionDef(func) # 484μs -> 462μs (4.70% faster)
    for i in range(n):
        lineno = 9000 + i
        if i % 2 == 0:
            pass
        else:
            pass
# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.
#------------------------------------------------
import ast
from pathlib import Path

# imports
import pytest  # used for our unit tests
from codeflash.code_utils.edit_generated_tests import CommentMapper

# function to test (see above for definition of CommentMapper and visit_AsyncFunctionDef)

# Helper function to create a dummy GeneratedTests object with a behavior_file_path
class DummyGeneratedTests:
    def __init__(self, path: str):
        self.behavior_file_path = Path(path)

# Helper function to create an AsyncFunctionDef node with a given body
def make_async_func(name, body_nodes):
    return ast.AsyncFunctionDef(
        name=name,
        args=ast.arguments(posonlyargs=[], args=[], kwonlyargs=[], kw_defaults=[], defaults=[]),
        body=body_nodes,
        decorator_list=[],
        returns=None,
        type_comment=None,
    )

# Helper function to create a simple statement node with a lineno
def make_simple_stmt(lineno):
    node = ast.Expr(value=ast.Constant(value=lineno))
    node.lineno = lineno
    return node

# Helper function to create a compound statement (e.g., ast.With) with a body and linenos
def make_with_stmt(lineno, body_nodes):
    node = ast.With(items=[], body=body_nodes)
    node.lineno = lineno
    for i, n in enumerate(body_nodes):
        n.lineno = lineno + i + 1
    return node

# Helper function to create a For loop with a body and linenos
def make_for_stmt(lineno, body_nodes):
    node = ast.For(target=ast.Name(id='x'), iter=ast.Name(id='y'), body=body_nodes, orelse=[])
    node.lineno = lineno
    for i, n in enumerate(body_nodes):
        n.lineno = lineno + i + 1
    return node

# Helper function to create an If statement with a body and linenos
def make_if_stmt(lineno, body_nodes):
    node = ast.If(test=ast.Constant(value=True), body=body_nodes, orelse=[])
    node.lineno = lineno
    for i, n in enumerate(body_nodes):
        n.lineno = lineno + i + 1
    return node

# Helper function to create an Assign node
def make_assign(lineno):
    node = ast.Assign(targets=[ast.Name(id='a')], value=ast.Constant(value=1))
    node.lineno = lineno
    return node

# ----------- BASIC TEST CASES -----------

def test_basic_single_async_function_with_one_statement():
    # Test a simple async function with a single statement
    test = DummyGeneratedTests("foo.py")
    original_runtimes = {"myfunc#.foo#0": 100,}
    optimized_runtimes = {"myfunc#.foo#0": 50,}
    node = make_async_func("myfunc", [make_simple_stmt(10)])
    mapper = CommentMapper(test, original_runtimes, optimized_runtimes)
    codeflash_output = mapper.visit_AsyncFunctionDef(node); result_node = codeflash_output # 5.10μs -> 5.13μs (0.565% slower)

def test_basic_async_function_with_multiple_statements():
    # Test async function with multiple statements
    test = DummyGeneratedTests("bar.py")
    original_runtimes = {
        "func#.bar#0": 200,
        "func#.bar#1": 300,
    }
    optimized_runtimes = {
        "func#.bar#0": 100,
        "func#.bar#1": 150,
    }
    node = make_async_func("func", [make_simple_stmt(5), make_simple_stmt(6)])
    mapper = CommentMapper(test, original_runtimes, optimized_runtimes)
    mapper.visit_AsyncFunctionDef(node) # 5.43μs -> 5.34μs (1.69% faster)

def test_basic_async_function_with_compound_statement():
    # Test async function with a compound statement (With)
    test = DummyGeneratedTests("baz.py")
    original_runtimes = {
        "compfunc#.baz#0_0": 400,
    }
    optimized_runtimes = {
        "compfunc#.baz#0_0": 200,
    }
    with_body = [make_simple_stmt(20)]
    node = make_async_func("compfunc", [make_with_stmt(10, with_body)])
    mapper = CommentMapper(test, original_runtimes, optimized_runtimes)
    mapper.visit_AsyncFunctionDef(node) # 6.11μs -> 5.24μs (16.6% faster)

# ----------- EDGE TEST CASES -----------

def test_edge_no_matching_runtimes():
    # No matching runtimes; results should be empty
    test = DummyGeneratedTests("edge.py")
    original_runtimes = {}
    optimized_runtimes = {}
    node = make_async_func("edgefunc", [make_simple_stmt(100)])
    mapper = CommentMapper(test, original_runtimes, optimized_runtimes)
    mapper.visit_AsyncFunctionDef(node) # 4.76μs -> 4.59μs (3.73% faster)

def test_edge_missing_optimized_runtime():
    # Only original runtime present; should not add comment
    test = DummyGeneratedTests("edge2.py")
    original_runtimes = {"func#.edge2#0": 100}
    optimized_runtimes = {}
    node = make_async_func("func", [make_simple_stmt(101)])
    mapper = CommentMapper(test, original_runtimes, optimized_runtimes)
    mapper.visit_AsyncFunctionDef(node) # 4.71μs -> 4.57μs (3.06% faster)

def test_edge_missing_original_runtime():
    # Only optimized runtime present; should not add comment
    test = DummyGeneratedTests("edge3.py")
    original_runtimes = {}
    optimized_runtimes = {"func#.edge3#0": 50}
    node = make_async_func("func", [make_simple_stmt(102)])
    mapper = CommentMapper(test, original_runtimes, optimized_runtimes)
    mapper.visit_AsyncFunctionDef(node) # 4.62μs -> 4.36μs (5.99% faster)

def test_edge_compound_with_multiple_body_statements():
    # Compound statement with multiple body statements, some with matching runtimes
    test = DummyGeneratedTests("edge4.py")
    original_runtimes = {
        "func#.edge4#0_0": 100,
        "func#.edge4#0_1": 200,
    }
    optimized_runtimes = {
        "func#.edge4#0_0": 50,
        "func#.edge4#0_1": 100,
    }
    with_body = [make_simple_stmt(110), make_simple_stmt(111)]
    node = make_async_func("func", [make_with_stmt(100, with_body)])
    mapper = CommentMapper(test, original_runtimes, optimized_runtimes)
    mapper.visit_AsyncFunctionDef(node) # 6.92μs -> 5.79μs (19.6% faster)

def test_edge_nested_compound_statements():
    # Nested compound statements (With inside For)
    test = DummyGeneratedTests("edge5.py")
    original_runtimes = {
        "func#.edge5#0_0": 100,
        "func#.edge5#0_0_0": 200,
    }
    optimized_runtimes = {
        "func#.edge5#0_0": 50,
        "func#.edge5#0_0_0": 100,
    }
    inner_with_body = [make_simple_stmt(210)]
    inner_with = make_with_stmt(200, inner_with_body)
    for_body = [inner_with]
    node = make_async_func("func", [make_for_stmt(100, for_body)])
    mapper = CommentMapper(test, original_runtimes, optimized_runtimes)
    mapper.visit_AsyncFunctionDef(node) # 6.27μs -> 5.32μs (17.9% faster)

def test_edge_assign_in_compound_body():
    # Compound statement with an Assign node in body
    test = DummyGeneratedTests("edge6.py")
    original_runtimes = {
        "func#.edge6#0_0": 300,
    }
    optimized_runtimes = {
        "func#.edge6#0_0": 100,
    }
    assign_node = make_assign(310)
    with_body = [assign_node]
    node = make_async_func("func", [make_with_stmt(300, with_body)])
    mapper = CommentMapper(test, original_runtimes, optimized_runtimes)
    mapper.visit_AsyncFunctionDef(node) # 5.61μs -> 5.02μs (11.8% faster)

def test_edge_function_with_no_body():
    # Function with empty body
    test = DummyGeneratedTests("edge7.py")
    original_runtimes = {}
    optimized_runtimes = {}
    node = make_async_func("func", [])
    mapper = CommentMapper(test, original_runtimes, optimized_runtimes)
    mapper.visit_AsyncFunctionDef(node) # 3.60μs -> 3.64μs (1.10% slower)

def test_edge_function_with_if_statement_and_body():
    # Function with If statement containing two body statements, one matched
    test = DummyGeneratedTests("edge8.py")
    original_runtimes = {
        "func#.edge8#0_1": 500,
    }
    optimized_runtimes = {
        "func#.edge8#0_1": 250,
    }
    if_body = [make_simple_stmt(401), make_simple_stmt(402)]
    node = make_async_func("func", [make_if_stmt(400, if_body)])
    mapper = CommentMapper(test, original_runtimes, optimized_runtimes)
    mapper.visit_AsyncFunctionDef(node) # 6.86μs -> 5.65μs (21.5% faster)

def test_edge_function_with_while_loop_and_body():
    # Function with While loop containing two body statements, both matched
    test = DummyGeneratedTests("edge9.py")
    original_runtimes = {
        "func#.edge9#0_0": 600,
        "func#.edge9#0_1": 700,
    }
    optimized_runtimes = {
        "func#.edge9#0_0": 300,
        "func#.edge9#0_1": 350,
    }
    while_body = [make_simple_stmt(501), make_simple_stmt(502)]
    node = make_async_func("func", [ast.While(test=ast.Constant(value=True), body=while_body, orelse=[], lineno=500)])
    mapper = CommentMapper(test, original_runtimes, optimized_runtimes)
    mapper.visit_AsyncFunctionDef(node) # 6.69μs -> 5.62μs (19.1% faster)

# ----------- LARGE SCALE TEST CASES -----------

def test_large_scale_many_statements():
    # Async function with many statements, all matched
    test = DummyGeneratedTests("large.py")
    N = 500  # Large but not excessive
    original_runtimes = {f"func#.large#{i}": 1000 + i for i in range(N)}
    optimized_runtimes = {f"func#.large#{i}": 500 + i for i in range(N)}
    stmts = [make_simple_stmt(1000 + i) for i in range(N)]
    node = make_async_func("func", stmts)
    mapper = CommentMapper(test, original_runtimes, optimized_runtimes)
    mapper.visit_AsyncFunctionDef(node) # 184μs -> 161μs (14.2% faster)
    for lineno in range(1000, 1000 + N):
        pass

def test_large_scale_many_compound_statements():
    # Async function with many compound statements, each with a body of 2 statements
    test = DummyGeneratedTests("large2.py")
    N = 200  # 200 compound statements x 2 = 400 statements
    original_runtimes = {}
    optimized_runtimes = {}
    stmts = []
    for i in range(N):
        body_nodes = [make_simple_stmt(2000 + 2*i), make_simple_stmt(2000 + 2*i + 1)]
        # Add runtime keys for each body statement
        original_runtimes[f"func#.large2#{i}_0"] = 100 + i
        optimized_runtimes[f"func#.large2#{i}_0"] = 50 + i
        original_runtimes[f"func#.large2#{i}_1"] = 200 + i
        optimized_runtimes[f"func#.large2#{i}_1"] = 100 + i
        stmts.append(make_with_stmt(1000 + i, body_nodes))
    node = make_async_func("func", stmts)
    mapper = CommentMapper(test, original_runtimes, optimized_runtimes)
    mapper.visit_AsyncFunctionDef(node) # 282μs -> 194μs (45.4% faster)
    for i in range(N):
        pass

def test_large_scale_nested_compounds():
    # Async function with nested compound statements (For inside With), each with 2 statements
    test = DummyGeneratedTests("large3.py")
    N = 100  # 100 withs, each with a for containing 2 stmts
    original_runtimes = {}
    optimized_runtimes = {}
    stmts = []
    for i in range(N):
        for_body = [make_simple_stmt(3000 + 2*i), make_simple_stmt(3000 + 2*i + 1)]
        original_runtimes[f"func#.large3#{i}_0_0"] = 100 + i
        optimized_runtimes[f"func#.large3#{i}_0_0"] = 50 + i
        original_runtimes[f"func#.large3#{i}_0_1"] = 200 + i
        optimized_runtimes[f"func#.large3#{i}_0_1"] = 100 + i
        for_stmt = make_for_stmt(2000 + i, for_body)
        stmts.append(make_with_stmt(1000 + i, [for_stmt]))
    node = make_async_func("func", stmts)
    mapper = CommentMapper(test, original_runtimes, optimized_runtimes)
    mapper.visit_AsyncFunctionDef(node) # 152μs -> 70.1μs (117% faster)
    for i in range(N):
        pass

def test_large_scale_performance():
    # Performance test: ensure function runs efficiently for large input
    import time
    test = DummyGeneratedTests("perf.py")
    N = 500
    original_runtimes = {f"func#.perf#{i}": 1000 + i for i in range(N)}
    optimized_runtimes = {f"func#.perf#{i}": 500 + i for i in range(N)}
    stmts = [make_simple_stmt(10000 + i) for i in range(N)]
    node = make_async_func("func", stmts)
    mapper = CommentMapper(test, original_runtimes, optimized_runtimes)
    start = time.time()
    mapper.visit_AsyncFunctionDef(node) # 185μs -> 162μs (14.2% faster)
    elapsed = time.time() - start
# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.

To edit these changes git checkout codeflash/optimize-pr687-2025-09-03T05.48.05 and push.

Codeflash

…#687 (`granular-async-instrumentation`)

The optimized code achieves an 11% speedup through several key micro-optimizations that reduce Python's runtime overhead:

**1. Cached Attribute/Dictionary Lookups**
The most impactful change is caching frequently accessed attributes and dictionaries as local variables:
- `context_stack = self.context_stack`
- `results = self.results` 
- `original_runtimes = self.original_runtimes`
- `optimized_runtimes = self.optimized_runtimes`
- `get_comment = self.get_comment`

This eliminates repeated `self.` attribute lookups in the tight loops, which the profiler shows are called thousands of times (2,825+ iterations).

**2. Pre-cached Loop Bodies**
Caching `node_body = node.body` and `ln_body = line_node.body` before loops reduces attribute access overhead. The profiler shows these are accessed in nested loops with high hit counts.

**3. Optimized String Operations**
Using f-strings (`f"{test_qualified_name}#{self.abs_path}"`, `f"{i}_{j}"`) instead of string concatenation with `+` operators reduces temporary object creation and string manipulation overhead.

**4. Refined getattr Usage**
Changed from `getattr(compound_line_node, "body", [])` to `getattr(compound_line_node, 'body', None)` with a conditional check, avoiding allocation of empty lists when no body exists.

**Performance Impact by Test Type:**
- **Large-scale tests** show the biggest gains (14-117% faster) due to the cumulative effect of micro-optimizations in loops
- **Compound statement tests** benefit significantly (16-45% faster) from reduced attribute lookups in nested processing  
- **Simple cases** show modest improvements (1-6% faster) as overhead reduction is less pronounced
- **Edge cases** with no matching runtimes benefit from faster loop traversal (3-12% faster)

The optimizations are most effective for functions with many statements or nested compound structures, where the tight loops amplify the benefit of reduced Python interpreter overhead.
@codeflash-ai codeflash-ai bot added the ⚡️ codeflash Optimization PR opened by Codeflash AI label Sep 3, 2025
@misrasaurabh1
Copy link
Contributor

too big of a change and seems like microoptimizations

@KRRT7 KRRT7 closed this Sep 3, 2025
@codeflash-ai codeflash-ai bot deleted the codeflash/optimize-pr687-2025-09-03T05.48.05 branch September 3, 2025 17:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
⚡️ codeflash Optimization PR opened by Codeflash AI
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants